package service

import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"soffice/config"
	"strings"
	"sync"
	"syscall"
	"time"

	md "github.com/JohannesKaufmann/html-to-markdown"
	"github.com/google/uuid"
	"github.com/yuin/goldmark"
	"github.com/yuin/goldmark/extension"
	"github.com/yuin/goldmark/renderer/html"
)

// DecodeBase64Image 解码base64图片数据
func DecodeBase64Image(data string) ([]byte, error) {
	return decodeBase64(data)
}

// decodeBase64 是基础解码实现
func decodeBase64(data string) ([]byte, error) {
	// 去除可能的换行和空格
	data = strings.ReplaceAll(data, "\n", "")
	data = strings.ReplaceAll(data, " ", "")
	return base64.StdEncoding.DecodeString(data)
}

// RemoteConvertPDFToHTML 远程调用PDF转HTML接口，返回ConvertResponse所需内容
func RemoteConvertPDFToHTML(files []*multipart.FileHeader) (success bool, htmlContent, originalFileName, htmlFileName, htmlFilePath, errorMsg string) {
	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)
	for _, fileHeader := range files {
		file, err := fileHeader.Open()
		if err != nil {
			errorMsg = "读取文件失败: " + err.Error()
			return
		}
		defer file.Close()
		part, err := writer.CreateFormFile("files", fileHeader.Filename)
		if err != nil {
			errorMsg = "创建表单文件失败: " + err.Error()
			return
		}
		if _, err := io.Copy(part, file); err != nil {
			errorMsg = "写入表单文件失败: " + err.Error()
			return
		}
	}
	writer.WriteField("to_formats", "html")
	writer.WriteField("do_ocr", "false")
	writer.Close()

	remoteURL := os.Getenv("REMOTE_PDF_API_URL")
	if remoteURL == "" {
		remoteURL = "http://10.11.3.68:5001/v1/convert/file" // 默认值
	}
	req, err := http.NewRequest("POST", remoteURL, &buf)
	if err != nil {
		errorMsg = "创建请求失败: " + err.Error()
		return
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		errorMsg = "远程接口调用失败: " + err.Error()
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		errorMsg = fmt.Sprintf("远程接口返回错误: %d", resp.StatusCode)
		return
	}

	var remoteResult struct {
		Document struct {
			Filename       string  `json:"filename"`
			MdContent      *string `json:"md_content"`
			JsonContent    *string `json:"json_content"`
			HtmlContent    *string `json:"html_content"`
			TextContent    *string `json:"text_content"`
			DoctagsContent *string `json:"doctags_content"`
		} `json:"document"`
		Status         string                 `json:"status"`
		Errors         []string               `json:"errors"`
		ProcessingTime float64                `json:"processing_time"`
		Timings        map[string]interface{} `json:"timings"`
	}
	decoder := json.NewDecoder(resp.Body)
	if err := decoder.Decode(&remoteResult); err != nil {
		errorMsg = "解析远程返回内容失败: " + err.Error()
		return
	}

	htmlContent = ""
	if remoteResult.Document.HtmlContent != nil {
		htmlContent = *remoteResult.Document.HtmlContent
	}
	success = remoteResult.Status == "success"
	originalFileName = remoteResult.Document.Filename
	htmlFileName = GenerateUniqueFileName(".html")
	htmlFilePath = ""

	// 处理base64图片并替换img src为URL
	if success && htmlContent != "" {
		// 创建静态图片目录
		uuid16 := GenerateUniqueFileName("")
		staticDir := filepath.Join("static", uuid16)
		if err := EnsureStorageDir(staticDir); err == nil {
			// 匹配所有base64图片
			imgRegex := regexp.MustCompile(`<img[^>]*src=["']data:image/(\w+);base64,([^"']+)["'][^>]*>`)
			idx := 0
			htmlContent = imgRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
				sub := imgRegex.FindStringSubmatch(match)
				if len(sub) < 3 {
					return match
				}
				ext := sub[1]
				base64Data := sub[2]
				imgBytes, err := DecodeBase64Image(base64Data)
				if err != nil {
					return match
				}
				imgName := fmt.Sprintf("img_%d.%s", idx, ext)
				idx++

				// 构建存储路径
				storagePath := filepath.Join(uuid16, imgName)

				// 保存图片到存储
				imgURL, err := SaveImageToStorage(imgBytes, storagePath)
				if err != nil {
					return match
				}

				// 替换src为URL
				return regexp.MustCompile(`src=["']data:image/\w+;base64,[^"']+["']`).ReplaceAllString(match, fmt.Sprintf(`src="%s"`, imgURL))
			})
		}

		// 将转换后的HTML写入out目录
		outputDir := "out"
		if err := EnsureDirExists(outputDir); err != nil {
			errorMsg = "创建输出目录失败: " + err.Error()
			success = false
			return
		}

		htmlFilePath = filepath.Join(outputDir, htmlFileName)
		if err := os.WriteFile(htmlFilePath, []byte(htmlContent), 0644); err != nil {
			errorMsg = "写入HTML文件失败: " + err.Error()
			htmlFilePath = ""
			success = false
			return
		}
	}

	if !success {
		if len(remoteResult.Errors) > 0 {
			errorMsg = strings.Join(remoteResult.Errors, "; ")
		} else {
			errorMsg = "转换失败"
		}
	}
	return
}

// 支持的文件格式
var allowedFormats = []string{"pdf", "doc", "docx", "odt", "odp", "pptx", "ppt", "ods", "xlsx", "xls", "md"}

var markdownConverter = goldmark.New(
	goldmark.WithExtensions(extension.GFM),
	goldmark.WithRendererOptions(
		html.WithHardWraps(),
		html.WithUnsafe(), // allow raw HTML passthrough for fidelity
	),
)

// 配置常量
const (
	MaxFileSize    = 4 * 50 * 1024 * 1024 // 200MB
	ConvertTimeout = 30 * time.Minute     // 转换超时时间
)

// 并发控制 - 简化版本
var (
	concurrencySemaphore chan struct{}
	initOnce             sync.Once
)

// 初始化并发控制
func initConcurrency() {
	initOnce.Do(func() {
		maxConcurrency := runtime.NumCPU()
		if maxConcurrency > 6 {
			maxConcurrency = 6 // 限制最大并发数
		}
		concurrencySemaphore = make(chan struct{}, maxConcurrency)
	})
}

// 获取环境变量或使用默认值
func GetBaseURL() string {
	if baseURL := os.Getenv("BASE_URL"); baseURL != "" {
		return baseURL
	}
	return "http://localhost:18420"
}

// 确保目录存在
func EnsureDirExists(dirPath string) error {
	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
		return os.MkdirAll(dirPath, 0755)
	}
	return nil
}

// 检查文件格式是否支持
func IsAllowedFormat(filename string) bool {
	ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(filename), "."))
	for _, format := range allowedFormats {
		if ext == format {
			return true
		}
	}
	return false
}

// ComputeFileHash 返回上传文件内容的SHA-256哈希值
func ComputeFileHash(file *multipart.FileHeader) (string, error) {
	src, err := file.Open()
	if err != nil {
		return "", err
	}
	defer src.Close()

	hasher := sha256.New()
	if _, err := io.Copy(hasher, src); err != nil {
		return "", err
	}

	return hex.EncodeToString(hasher.Sum(nil)), nil
}

// 保存上传的文件
func SaveUploadedFile(file *multipart.FileHeader, dst string) error {
	src, err := file.Open()
	if err != nil {
		return err
	}
	defer src.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, src)
	return err
}

// ConvertPDFToDocx 使用 pdf2docx 将 PDF 转换为 DOCX
func ConvertPDFToDocx(inputFilePath string) (string, error) {
	// 获取文件名
	fileName := filepath.Base(inputFilePath)
	fileNameWithoutExt := strings.TrimSuffix(fileName, filepath.Ext(fileName))

	// 创建临时目录存放 DOCX 文件
	tempDir := filepath.Join("/tmp", "pdf2docx_"+uuid.New().String()[:8])
	if err := os.MkdirAll(tempDir, 0755); err != nil {
		return "", fmt.Errorf("创建临时目录失败: %v", err)
	}

	outputFilePath := filepath.Join(tempDir, fileNameWithoutExt+".docx")

	// 获取Python脚本路径
	scriptPath := filepath.Join("scripts", "pdf_converter.py")
	if _, err := os.Stat(scriptPath); os.IsNotExist(err) {
		// 如果在当前目录找不到，尝试在容器内的路径
		scriptPath = "/app/scripts/pdf_converter.py"
	}

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), ConvertTimeout)
	defer cancel()

	// 执行 Python 脚本,将 PDF 转换为 DOCX
	cmd := exec.CommandContext(ctx, "python3", scriptPath, inputFilePath, "-o", outputFilePath, "--json")

	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		// 清理临时目录
		os.RemoveAll(tempDir)
		return "", fmt.Errorf("pdf2docx 转换失败: %v\nstdout: %s\nstderr: %s", err, stdout.String(), stderr.String())
	}

	// 解析 JSON 输出
	var result struct {
		Success    bool   `json:"success"`
		Error      string `json:"error"`
		OutputPath string `json:"output_path"`
	}

	if err := json.Unmarshal(stdout.Bytes(), &result); err != nil {
		os.RemoveAll(tempDir)
		return "", fmt.Errorf("解析转换结果失败: %v", err)
	}

	if !result.Success {
		os.RemoveAll(tempDir)
		return "", fmt.Errorf("pdf2docx 转换失败: %s", result.Error)
	}

	// 检查输出文件是否生成
	if _, err := os.Stat(outputFilePath); os.IsNotExist(err) {
		os.RemoveAll(tempDir)
		return "", fmt.Errorf("DOCX 文件未生成: %s", outputFilePath)
	}

	return outputFilePath, nil
}

// ConvertPDFWithPdf2Docx 使用 pdf2docx + LibreOffice 转换 PDF 到 HTML
// 先将 PDF 转为 DOCX，再用 LibreOffice 将 DOCX 转为 HTML
func ConvertPDFWithPdf2Docx(inputFilePath, outputDir string) error {
	// 第一步：使用 pdf2docx 将 PDF 转换为 DOCX
	docxFilePath, err := ConvertPDFToDocx(inputFilePath)
	if err != nil {
		return err
	}

	// 确保清理临时 DOCX 文件
	defer func() {
		tempDir := filepath.Dir(docxFilePath)
		os.RemoveAll(tempDir)
	}()

	// 第二步：使用 LibreOffice 将 DOCX 转换为 HTML
	if err := ConvertToHTML(docxFilePath, outputDir); err != nil {
		return fmt.Errorf("LibreOffice 转换 DOCX 到 HTML 失败: %v", err)
	}

	return nil
}

// 文件转换为HTML - 精简并发优化版本
// PDF 文件使用 pdf2docx + LibreOffice 进行转换，其他格式使用 LibreOffice
func ConvertToHTML(inputFilePath, outputDir string) error {
	// PDF 文件使用 pdf2docx + LibreOffice 转换
	if strings.EqualFold(filepath.Ext(inputFilePath), ".pdf") {
		return ConvertPDFWithPdf2Docx(inputFilePath, outputDir)
	}

	// 非 PDF 文件使用 LibreOffice 转换
	// 初始化并发控制
	initConcurrency()

	// 获取信号量，控制并发数
	concurrencySemaphore <- struct{}{}
	defer func() { <-concurrencySemaphore }()

	// 为每个转换任务创建独立的用户配置目录
	tempUserDir := filepath.Join("/tmp", "soffice_"+uuid.New().String()[:8])
	defer os.RemoveAll(tempUserDir) // 简化清理

	// 创建临时用户配置目录
	if err := os.MkdirAll(tempUserDir, 0755); err != nil {
		return fmt.Errorf("创建临时用户配置目录失败: %v", err)
	}

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), ConvertTimeout)
	defer cancel()

	// 使用独立的用户配置目录运行LibreOffice
	cmd := exec.CommandContext(ctx, "soffice",
		"--headless",
		"--convert-to", "html",
		inputFilePath,
		"--outdir", outputDir,
		"-env:UserInstallation=file://"+tempUserDir, // 关键：使用独立的用户配置目录
		"--norestore",
		"--nologo",
		"--invisible",
	)

	// 设置进程组，便于清理子进程 (Unix/Linux/macOS)
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	err := cmd.Run()
	if err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			return fmt.Errorf("转换超时（%v）", ConvertTimeout)
		}
		return fmt.Errorf("转换失败: %s", err.Error())
	}

	return nil
}

// ConvertMarkdownFileToHTML 使用 goldmark 将 Markdown 文件转换为 HTML 字符串
func ConvertMarkdownFileToHTML(markdownFilePath string) (string, error) {
	data, err := os.ReadFile(markdownFilePath)
	if err != nil {
		return "", fmt.Errorf("读取Markdown文件失败: %w", err)
	}

	var buf bytes.Buffer
	if err := markdownConverter.Convert(data, &buf); err != nil {
		return "", fmt.Errorf("markdown转换失败: %w", err)
	}

	htmlContent := buf.String()
	// 确保返回完整 HTML 结构,便于前端直接渲染
	if !strings.Contains(strings.ToLower(htmlContent), "<html") {
		htmlContent = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body>" + htmlContent + "</body></html>"
	}

	return htmlContent, nil
}

// ProcessMarkdownToHTML 完整处理 Markdown 转换流程,包括文件创建和保存
func ProcessMarkdownToHTML(uploadedFilePath, fileName, fileExt string) (htmlContent, outputHTMLPath string, err error) {
	outputDir := "out"
	if err = EnsureDirExists(outputDir); err != nil {
		err = fmt.Errorf("创建输出目录失败: %w", err)
		return
	}

	fileNameWithoutExt := strings.TrimSuffix(fileName, fileExt)
	outputHTMLPath = filepath.Join(outputDir, fileNameWithoutExt+".html")

	htmlContent, err = ConvertMarkdownFileToHTML(uploadedFilePath)
	if err != nil {
		return
	}

	if err = os.WriteFile(outputHTMLPath, []byte(htmlContent), 0644); err != nil {
		err = fmt.Errorf("写入HTML文件失败: %w", err)
		return
	}

	return
}

// ProcessBase64Images 处理 HTML 中的 base64 图片，将其保存到存储
func ProcessBase64Images(htmlContent, htmlFileName, staticDir, baseURL string) (string, error) {
	// 创建图片目录（仅本地存储需要）
	imageDir := filepath.Join(staticDir, strings.TrimSuffix(htmlFileName, filepath.Ext(htmlFileName)))
	if err := EnsureStorageDir(imageDir); err != nil {
		return htmlContent, err
	}

	// 匹配所有 base64 图片
	imgRegex := regexp.MustCompile(`<img[^>]*src=["']data:image/(\w+);base64,([^"']+)["'][^>]*>`)
	idx := 0
	htmlContent = imgRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
		sub := imgRegex.FindStringSubmatch(match)
		if len(sub) < 3 {
			return match
		}
		ext := sub[1]
		base64Data := sub[2]

		// 解码 base64 数据
		imgBytes, err := DecodeBase64Image(base64Data)
		if err != nil {
			log.Printf("解码 base64 图片失败: %v", err)
			return match
		}

		// 生成图片文件名和路径
		imgName := fmt.Sprintf("img_%d.%s", idx, ext)
		idx++

		// 构建存储路径
		dirName := strings.TrimSuffix(htmlFileName, filepath.Ext(htmlFileName))
		storagePath := filepath.Join(dirName, imgName)

		// 保存图片到存储
		imgURL, err := SaveImageToStorage(imgBytes, storagePath)
		if err != nil {
			log.Printf("保存图片失败: %v", err)
			return match
		}

		// 替换 src 为 URL
		return regexp.MustCompile(`src=["']data:image/\w+;base64,[^"']+["']`).ReplaceAllString(match, fmt.Sprintf(`src="%s"`, imgURL))
	})

	return htmlContent, nil
}

// ProcessHTMLImages 处理 HTML 中的图片路径
func ProcessHTMLImages(htmlContent, htmlFileName, outputDir, staticDir, baseURL string) (string, error) {
	// 创建图片目录（仅本地存储需要）
	imageDir := filepath.Join(staticDir, strings.TrimSuffix(htmlFileName, filepath.Ext(htmlFileName)))
	if err := EnsureStorageDir(imageDir); err != nil {
		return htmlContent, err
	}

	// 匹配HTML中的img标签
	imgRegex := regexp.MustCompile(`<img([^>]*?)src=["']([^"']*?)["']([^>]*?)>`)

	return imgRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
		matches := imgRegex.FindStringSubmatch(match)
		if len(matches) < 4 {
			return match
		}

		beforeSrc := matches[1]
		originalSrc := matches[2]
		afterSrc := matches[3]

		// 跳过已经是完整URL的图片
		if strings.HasPrefix(originalSrc, "http") || strings.HasPrefix(originalSrc, "data:") || strings.HasPrefix(originalSrc, "/") {
			return match
		}

		// 构建原始图片路径
		originalImagePath := filepath.Join(outputDir, originalSrc)
		if _, err := os.Stat(originalImagePath); os.IsNotExist(err) {
			return match
		}

		// 生成新的图片文件名
		imageExt := filepath.Ext(originalSrc)
		newImageName := uuid.New().String()[:16] + imageExt

		// 构建存储路径
		dirName := strings.TrimSuffix(htmlFileName, filepath.Ext(htmlFileName))
		storagePath := filepath.Join(dirName, newImageName)

		// 复制图片到存储
		newSrc, err := CopyFileToStorage(originalImagePath, storagePath)
		if err != nil {
			log.Printf("复制图片失败: %v", err)
			return match
		}

		return fmt.Sprintf(`<img%ssrc="%s"%s>`, beforeSrc, newSrc, afterSrc)
	}), nil
}

// 复制文件
func CopyFile(src, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dstFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	return err
}

// 删除 title="header" 和 title="footer" 的 div 元素
func RemoveHeaderFooterDivs(html string) string {
	// 匹配 <div title="header">...</div> 和 <div title="footer">...</div>
	re := regexp.MustCompile(`(?s)<div\s+title=["'](?:header|footer)["'][^>]*>.*?</div>`) // (?s)让.匹配换行
	return re.ReplaceAllString(html, "")
}

// 清理临时文件
func CleanupTempFiles(outputDir, fileNameWithoutExt string) {
	files, err := os.ReadDir(outputDir)
	if err != nil {
		return
	}

	for _, file := range files {
		fileName := file.Name()
		if strings.HasPrefix(fileName, fileNameWithoutExt+"_html_") &&
			(strings.HasSuffix(fileName, ".png") || strings.HasSuffix(fileName, ".jpg") ||
				strings.HasSuffix(fileName, ".gif") || strings.HasSuffix(fileName, ".jpeg")) {

			imgPath := filepath.Join(outputDir, fileName)
			if err := os.Remove(imgPath); err != nil {
				log.Printf("删除临时图片失败 %s: %v", imgPath, err)
			} else {
				// log.Printf("已删除临时图片: %s", imgPath)
			}
		}
	}
}

// GenerateUniqueFileName 生成唯一文件名
func GenerateUniqueFileName(originalExt string) string {
	return uuid.New().String()[:16] + originalExt
}

// GetAllowedFormats 返回支持的文件格式列表
func GetAllowedFormats() []string {
	return allowedFormats
}

// ConvertHTMLStringToFile 将HTML字符串转换为PDF、Word或Markdown文件
// 会自动处理HTML中的图片，将URL图片转换为base64嵌入
func ConvertHTMLStringToFile(htmlContent, outputFormat string) (string, error) {
	outputFormat = strings.ToLower(outputFormat)

	// 如果是Markdown格式，使用专门的转换方法
	if outputFormat == "md" {
		return ConvertHTMLToMarkdown(htmlContent)
	}

	// 处理HTML中的图片，转换为base64
	processedHTML, err := ConvertImagesToBase64(htmlContent)
	if err != nil {
		log.Printf("转换图片为base64时出错: %v", err)
		// 继续处理，即使图片转换失败
	} else {
		htmlContent = processedHTML
	}

	// 创建临时HTML文件
	tempDir := filepath.Join("/tmp", "html_convert_"+uuid.New().String()[:8])
	if err := os.MkdirAll(tempDir, 0755); err != nil {
		return "", fmt.Errorf("创建临时目录失败: %v", err)
	}
	defer os.RemoveAll(tempDir)

	// 写入HTML文件
	htmlFilePath := filepath.Join(tempDir, "input.html")
	if err := os.WriteFile(htmlFilePath, []byte(htmlContent), 0644); err != nil {
		return "", fmt.Errorf("写入HTML文件失败: %v", err)
	}

	// 确定输出格式和转换参数
	var outputExt, convertParam string
	switch outputFormat {
	case "pdf":
		outputExt = "pdf"
		convertParam = "pdf"
	case "word", "docx":
		outputExt = "docx"
		convertParam = "docx:MS Word 2007 XML"
	default:
		return "", fmt.Errorf("不支持的输出格式: %s", outputFormat)
	}

	// 创建输出目录
	outputDir := "out"
	if err := EnsureDirExists(outputDir); err != nil {
		return "", fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 生成输出文件名
	outputFileName := GenerateUniqueFileName("." + outputExt)
	outputFilePath := filepath.Join(outputDir, outputFileName)

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), ConvertTimeout)
	defer cancel()

	// 使用soffice转换
	cmd := exec.CommandContext(ctx, "soffice",
		"--headless",
		"--convert-to", convertParam,
		htmlFilePath,
		"--outdir", outputDir,
	)

	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			return "", fmt.Errorf("转换超时（%v）", ConvertTimeout)
		}
		return "", fmt.Errorf("转换失败: %s, stderr: %s", err.Error(), stderr.String())
	}

	// soffice会使用原始文件名，需要重命名
	generatedFile := filepath.Join(outputDir, "input."+outputExt)
	if _, err := os.Stat(generatedFile); err == nil {
		if err := os.Rename(generatedFile, outputFilePath); err != nil {
			return "", fmt.Errorf("重命名输出文件失败: %v", err)
		}
	} else {
		return "", fmt.Errorf("输出文件未生成: %s", generatedFile)
	}

	return outputFilePath, nil
}

// ConvertHTMLToMarkdown 将HTML字符串转换为Markdown文件
func ConvertHTMLToMarkdown(htmlContent string) (string, error) {
	// 创建输出目录
	outputDir := "out"
	if err := EnsureDirExists(outputDir); err != nil {
		return "", fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 生成输出文件名
	outputFileName := GenerateUniqueFileName(".md")
	outputFilePath := filepath.Join(outputDir, outputFileName)

	// 简单的HTML到Markdown转换
	markdown := convertHTMLToMarkdownString(htmlContent)

	// 写入Markdown文件
	if err := os.WriteFile(outputFilePath, []byte(markdown), 0644); err != nil {
		return "", fmt.Errorf("写入Markdown文件失败: %v", err)
	}

	return outputFilePath, nil
}

// convertHTMLToMarkdownString 将HTML字符串转换为Markdown格式
func convertHTMLToMarkdownString(htmlContent string) string {
	converter := md.NewConverter("", true, nil)

	// 添加插件支持
	converter.Use(md.Plugin(func(c *md.Converter) []md.Rule {
		return []md.Rule{
			// 可以在这里添加自定义规则
		}
	}))

	markdown, err := converter.ConvertString(htmlContent)
	if err != nil {
		log.Printf("HTML转Markdown失败: %v", err)
		// 如果转换失败，返回原始内容
		return htmlContent
	}

	return strings.TrimSpace(markdown)
}

// ConvertImagesToBase64 将HTML中的图片URL转换为base64编码
func ConvertImagesToBase64(htmlContent string) (string, error) {
	// 匹配所有img标签
	imgRegex := regexp.MustCompile(`<img([^>]*?)src=["']([^"']*?)["']([^>]*?)>`)

	return imgRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
		matches := imgRegex.FindStringSubmatch(match)
		if len(matches) < 4 {
			return match
		}

		beforeSrc := matches[1]
		originalSrc := matches[2]
		afterSrc := matches[3]

		// 跳过已经是base64的图片
		if strings.HasPrefix(originalSrc, "data:") {
			return match
		}

		// 获取图片数据并转换为base64
		base64Data, mimeType, err := fetchImageAsBase64(originalSrc)
		if err != nil {
			log.Printf("获取图片失败 %s: %v", originalSrc, err)
			return match
		}

		// 替换为base64
		newSrc := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Data)
		return fmt.Sprintf(`<img%ssrc="%s"%s>`, beforeSrc, newSrc, afterSrc)
	}), nil
}

// fetchImageAsBase64 获取图片并转换为base64
func fetchImageAsBase64(imageSrc string) (string, string, error) {
	var imageData []byte
	var err error

	// 判断是URL还是本地路径
	if strings.HasPrefix(imageSrc, "http://") || strings.HasPrefix(imageSrc, "https://") {
		// 从URL获取
		resp, err := http.Get(imageSrc)
		if err != nil {
			return "", "", fmt.Errorf("下载图片失败: %v", err)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return "", "", fmt.Errorf("下载图片失败，状态码: %d", resp.StatusCode)
		}

		imageData, err = io.ReadAll(resp.Body)
		if err != nil {
			return "", "", fmt.Errorf("读取图片数据失败: %v", err)
		}
	} else {
		// 获取动态API基础路径
		apiBasePath := config.GetAPIBasePath()
		downloadFilePrefix := "/" + apiBasePath + "/download-file/"
		staticPrefix := apiBasePath + "/static/"

		// 处理服务内部路径（可能来自存储）
		if strings.HasPrefix(imageSrc, downloadFilePrefix) {
			// 从存储获取图片
			storagePath := strings.TrimPrefix(imageSrc, downloadFilePrefix)
			st := GetStorageInstance()

			reader, err := st.GetFile(storagePath)
			if err != nil {
				return "", "", fmt.Errorf("从存储获取图片失败 %s: %v", storagePath, err)
			}
			defer reader.Close()

			imageData, err = io.ReadAll(reader)
			if err != nil {
				return "", "", fmt.Errorf("读取存储图片数据失败: %v", err)
			}
		} else {
			// 从本地文件读取
			// 处理相对路径，尝试多个可能的位置
			possiblePaths := []string{}

			// 如果路径以/开头，说明是绝对路径（相对于服务根目录）
			if strings.HasPrefix(imageSrc, "/") {
				trimmedPath := strings.TrimPrefix(imageSrc, "/")

				// 处理动态 API 路径前缀
				if strings.HasPrefix(trimmedPath, staticPrefix) {
					// 去掉 API 基础路径前缀，直接使用 static/ 路径
					localPath := strings.TrimPrefix(trimmedPath, apiBasePath+"/")
					possiblePaths = append(possiblePaths, localPath)
				} else if strings.HasPrefix(trimmedPath, apiBasePath+"/") {
					// 其他 API 基础路径开头的路径
					possiblePaths = append(possiblePaths, strings.TrimPrefix(trimmedPath, apiBasePath+"/"))
				}

				// 也尝试原始去掉/的路径
				possiblePaths = append(possiblePaths, trimmedPath)
			} else {
				// 相对路径，尝试多个位置
				possiblePaths = append(possiblePaths,
					imageSrc,
					filepath.Join("static", imageSrc),
					filepath.Join(".", imageSrc),
				)
			}

			var foundPath string
			for _, path := range possiblePaths {
				if _, err := os.Stat(path); err == nil {
					foundPath = path
					break
				}
			}

			if foundPath == "" {
				return "", "", fmt.Errorf("找不到图片文件: %s (尝试路径: %v)", imageSrc, possiblePaths)
			}

			imageData, err = os.ReadFile(foundPath)
			if err != nil {
				return "", "", fmt.Errorf("读取图片文件失败: %v", err)
			}
		}
	}

	// 检测MIME类型
	mimeType := detectImageMimeType(imageSrc, imageData)

	// 转换为base64
	base64Str := base64.StdEncoding.EncodeToString(imageData)

	return base64Str, mimeType, nil
}

// detectImageMimeType 检测图片的MIME类型
func detectImageMimeType(filename string, data []byte) string {
	// 先根据文件扩展名判断
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	case ".gif":
		return "image/gif"
	case ".webp":
		return "image/webp"
	case ".svg":
		return "image/svg+xml"
	case ".bmp":
		return "image/bmp"
	}

	// 根据文件头判断
	if len(data) >= 8 {
		if data[0] == 0xFF && data[1] == 0xD8 {
			return "image/jpeg"
		}
		if data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 {
			return "image/png"
		}
		if data[0] == 0x47 && data[1] == 0x49 && data[2] == 0x46 {
			return "image/gif"
		}
	}

	return "image/jpeg" // 默认
}
